﻿// Copyright (c) 2008 Interact Software Ltd.

// Permission is hereby granted, free of charge, to any person obtaining a copy of this software
// and associated documentation files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
// BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 

// Dynamic Bitmap Generation for Silverlight
// =========================================
// See http://www.codeplex.com/SlDynamicBitmap for details.

using System;

namespace InteractSw.GenerateBitmap
{
    /// <summary>
    /// Implements the 32-bit cyclic redundancy check used by PNG chunks.
    /// </summary>
    /// <remarks>
    /// PNG appears to use the same CRC as IEEE 802.3, V.42 and MPEG-2.
    /// 
    /// Irritatingly there are at least 2 implementations of this already in .NET, but
    /// they're not public...
    /// </remarks>
    static class Crc32
    {
        /// <summary>
        /// Table of CRCs of all 8-bit messages.
        /// </summary>
        static uint[] CrcTable = MakeCrcTable();


        /// <summary>
        /// Precalculate a table for fast CRC generation.
        /// </summary>
        private static uint[] MakeCrcTable()
        {
            uint[] table = new uint[256];

            for (int i = 0; i < table.Length; i++)
            {
                uint current = (uint) i;
                for (int k = 0; k < 8; k++)
                {
                    if ((current & 1) != 0)
                    {
                        current = 0xedb88320 ^ (current >> 1);
                    }
                    else
                    {
                        current = current >> 1;
                    }
                }
                table[i] = current;
            }
            return table;
        }

        /// <summary>
        /// Updates a running CRC.
        /// </summary>
        /// <param name="crc">Current CRC value. Use 0xffffffff if this is the first
        /// run of bytes.</param>
        /// <param name="buffer">Bytes to be added into the current CRC.</param>
        /// <returns>The current CRC. Once done chaining CRC runs together,
        /// XOR this with 0xffffffff to get the final output.</returns>
        public static uint UpdateCrc(uint crc, byte[] buffer)
        {
            for (int i = 0; i < buffer.Length; i++)
            {
                crc = CrcTable[(crc ^ buffer[i]) & 0xff] ^ (crc >> 8);
            }
            return crc;
        }

        /// <summary>
        /// Calculates the CRC for the data provided.
        /// </summary>
        /// <param name="buffer">Data for which to calculate the CRC.</param>
        /// <returns>The CRC for this data.</returns>
        public static uint Crc(byte[] buffer)
        {
            return UpdateCrc(0xffffffff, buffer) ^ 0xffffffff;
        }

    }
}
